/* eslint-disable @typescript-eslint/no-explicit-any */
import { TargetedEvent, useCallback, useEffect, useRef } from 'preact/compat';
import { useComputed, useSignal } from '@preact/signals';
import autosize from 'autosize';
import { Namespace } from '../../utils';
import { AudioSvg, RecordingSvg, SendSvg } from '../../icons';
import { AiChatController } from '../../controller';
import './chat-input.scss';

export interface ChatInputProps {
  /**
   * 单实例聊天总控
   *
   * @author chitanda
   * @date 2023-10-13 17:10:43
   * @type {AiChatController}
   */
  controller: AiChatController;
}

const ns = new Namespace('chat-input');

// 语音识别构造器
const SpeechRecognition =
  (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;

export const ChatInput = (props: ChatInputProps) => {
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  const input = props.controller.input;

  const isLoading = useSignal(false);

  // 是否正在语音输入
  const recording = useSignal(false);

  // 语音识别实例
  const recognition = useRef<any>();

  if (SpeechRecognition && !recognition.current) {
    recognition.current = new SpeechRecognition();

    recognition.current.onstart = () => {
      recording.value = true;
    };

    recognition.current.onend = () => {
      recording.value = false;
    };

    recognition.current.onresult = (e: any) => {
      const transcript = e.results?.[0]?.[0]?.transcript;
      if (transcript) {
        input.value = `${input.value}${transcript}`;
      }
    };
  }

  // 处理语音输入按钮点击事件
  const handleRecordButtonClick = () => {
    if (recognition.current && !recording.value) {
      recognition.current.start();
    }
  };

  const onInput = useCallback(
    (e: TargetedEvent<HTMLTextAreaElement, Event>) => {
      input.value = (e.target as HTMLTextAreaElement).value;
    },
    [input],
  );

  const isDisableSend = useComputed(
    () => input.value.length <= 0 || isLoading.value === true,
  );

  useEffect(() => {
    if (textareaRef.current) {
      autosize(textareaRef.current);
    }
    return () => {
      if (textareaRef.current) {
        autosize.destroy(textareaRef.current);
      }
    };
  }, [textareaRef]);

  const question = useCallback(async () => {
    isLoading.value = true;
    try {
      await props.controller.question(input.value);
      input.value = '';
    } catch (err) {
      console.error(err);
    } finally {
      isLoading.value = false;
    }
  }, [input, isLoading]);

  const onKeyDown = (e: KeyboardEvent) => {
    if (e.code === 'Enter') {
      e.stopPropagation();
      if (e.shiftKey === false) {
        question();
      }
    }
  };

  return (
    <div className={ns.b()}>
      <textarea
        className={ns.e('textarea')}
        type='text'
        rows={6}
        autoCorrect='off'
        autoCapitalize='off'
        autoComplete='off'
        value={input}
        onInput={onInput}
        onKeyDown={onKeyDown}
        ref={textareaRef}
        disabled={isLoading}
      />
      <div className={ns.b('action-wrapper')}>
        <div
          title={recording.value ? '语音输入中...' : '语音输入'}
          className={`${ns.be('action-wrapper', 'action-item')}`}
          onClick={handleRecordButtonClick}
        >
          {recording.value ? <RecordingSvg /> : <AudioSvg />}
        </div>
        <div
          title={isLoading.value ? '思考中...' : '发送消息'}
          className={`${ns.be('action-wrapper', 'action-item')} ${ns.is(
            'disabled',
            isDisableSend.value,
          )} ${ns.is('loading', isLoading.value)}`}
          onClick={question}
          disabled={isDisableSend}
        >
          <SendSvg />
        </div>
      </div>
    </div>
  );
};
